#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "math.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"
#include "AUfeatureterm.h"
#include "FT_refinement.h"
#include "FT_generalization.h"

#include "psm.h"
#include "rINDUCTION.h"


bool rINDUCTIONHypothesis::learn(List<FeatureTerm> *cases,Path *description_path,Path *solution_path,Ontology *o,FTKBase *domain_model)
{
	FeatureTerm *solution;
	List<FeatureTerm> solutions;
	List< List<FeatureTerm> > descriptions;
	List<FeatureTerm> positive;
	List<FeatureTerm> negative;


	/* Compute the different solutions: */ 
	{
		int pos;
		FeatureTerm *c,*s,*d;
		List<FeatureTerm> l,*tmp;

		l.Instance(*cases);
		while(l.Iterate(c)) {
/*
			{
				char *s=c->toStringNOOS(domain_model);
				printf("%s\n",s);
				delete []s;
			}
*/			
			tmp=c->readPath(description_path);
			if (tmp->Length()==1) d=tmp->ExtractIni();
							 else d=0;
			delete tmp;
			tmp=c->readPath(solution_path);
			if (tmp->Length()==1) s=tmp->ExtractIni();
							 else s=0;
			delete tmp;
			
			pos=solutions.Position(s);
			if (pos==-1) {
				solutions.Add(s);
				tmp=new List<FeatureTerm>;
				tmp->Add(d);
				descriptions.Add(tmp);
			} else {
				delete s;
				descriptions[pos]->Add(d);
			} /* if */ 
		} /* while */ 
	}

	/* Compute the default solution: */ 
	{
		int max=-1;
		FeatureTerm *s;
		List<FeatureTerm> *tmp;

		m_default_solution=0;

		solutions.Rewind();
		descriptions.Rewind();

		while(solutions.Iterate(s) &&  descriptions.Iterate(tmp)) {
			if (max==-1 || tmp->Length()>max) {
				max=tmp->Length();
				delete m_default_solution;
				m_default_solution=new FeatureTerm(s);
			} /* if */ 
		} /* while */ 
	}

	solutions.Rewind();
	while(solutions.Iterate(solution)) {
		learn_single_class(solution,cases,description_path,solution_path,o,domain_model);
	} /* while */ 

	return true;
} /* rINDUCTIONHypothesis::learn */ 


bool rINDUCTIONHypothesis::learn_single_class(FeatureTerm *solution,List<FeatureTerm> *cases,Path *description_path,Path *solution_path,Ontology *o,FTKBase *domain_model)
{
	List<FeatureTerm> positive;
	List<FeatureTerm> negative;

	/* Learn a set of patterns for the current solution: */ 
	{
		char *s=solution->toStringNOOS(domain_model);
		printf("\nrINDUCTION: building model for %s --------------------------------------------------\n\n",s);
		delete []s;
	}

	/* Create the positive and negative examples lists: */ 
	{
		FeatureTerm *c,*s,*d;
		List<FeatureTerm> l,*tmp;

		l.Instance(*cases);
		while(l.Iterate(c)) {
			tmp=c->readPath(description_path);
			if (tmp->Length()==1) d=tmp->ExtractIni();
							 else d=0;
			delete tmp;
			tmp=c->readPath(solution_path);
			if (tmp->Length()==1) s=tmp->ExtractIni();
							 else s=0;
			delete tmp;

			if (solution->equivalents(s)) {
				positive.Add(d);
			} else {
				negative.Add(d);
			} /* if */ 
			delete s;
		} /* while */ 
	}


	if (negative.EmptyP()) {
		FeatureTerm *pattern=new FeatureTerm((Symbol *)0,o->get_sort("any"),0);

		printf("rINDUCTION: rule found, covers %i positive examples\n",positive.Length());
		{
			char *s1,*s2;
			s1=solution->toStringNOOS(domain_model);
			s2=pattern->toStringNOOS(domain_model);
			printf("rINDUCTION: rule is for class %s,\n%s\n\n",s1,s2);
			delete []s1;
			delete []s2;
		}

		m_patterns.Add(pattern);
		m_solutions.Add(new FeatureTerm(solution));
		m_reliability.Add(new float(1));
		positive.Delete();
		negative.Delete();
	} else {

		/* Build patterns until all the positive examples have been covered: */ 
		while(!positive.EmptyP()) {
			printf("rINDUCTION: %i positive, %i negative\n",positive.Length(),negative.Length());

			/* find the shortest description that covers only positive examples: */ 
			{
				FeatureTerm *description,*d,*refinement,*problem;
				List<FeatureTerm> open_descriptions;
				List<FeatureTerm> *refinements;
				bool valid,is_solution;

				open_descriptions.Add(new FeatureTerm((Symbol *)0,o->get_sort("any"),0));

				do{
					description=open_descriptions.ExtractIni();
					refinements = DSpecializationL2_b(description,&positive,0,o,domain_model);

					while(!refinements->EmptyP()) {
						int positive_covered=0;

						refinement=refinements->ExtractIni();

						valid=false;
						positive.Rewind();
						while(positive.Iterate(problem) && !valid) {
							if (refinement->subsumes(problem)) valid=true;
						} /* while */ 

						if (valid) {
/*
							{
								char *s;
								s=refinement->toStringNOOS(domain_model);
								printf("Refinement:\n%s\n\n",s);
								delete []s;
							}
*/
							is_solution=true;
							negative.Rewind();
							while(negative.Iterate(problem) && is_solution) {
								if (refinement->subsumes(problem)) is_solution=false;
							} /* while */ 

							if (is_solution) {
								/* Solution found!!!: */ 
								m_patterns.Add(refinement);
								m_solutions.Add(new FeatureTerm(solution));
								m_reliability.Add(new float(1));

								{
									List<FeatureTerm> to_delete;
									FeatureTerm *f;

									positive.Rewind();
									while(positive.Iterate(problem)) {
										if (refinement->subsumes(problem)) {
											positive_covered++;
											to_delete.Add(problem);
										} /* if */ 
									} /* while */ 

									while(!to_delete.EmptyP()) {
										f=to_delete.ExtractIni();
										positive.DeleteElement(f);
										delete f;
									} /* while */ 
								}

								printf("rINDUCTION: new rule found , covers %i positive examples and %i negative examples\n",positive_covered,0);
								{
									char *s1,*s2;
									s1=solution->toStringNOOS(domain_model);
									s2=refinement->toStringNOOS(domain_model);
									printf("rFOIL: rule is for class %s,\n%s\n\n",s1,s2);
									delete []s1;
									delete []s2;
								}

								open_descriptions.Delete();
								refinements->Delete();
							} else {
								bool advances=true;

								open_descriptions.Rewind();
								while(open_descriptions.Iterate(d) && advances) {
									if (refinement->subsumes(d)) advances=false;
								} /* while */ 

								if (advances) {
									open_descriptions.Add(refinement);
								} else {
									delete refinement;
								} /* if */ 
							} /* if */ 
						} else {
							delete refinement;
						} /* if */ 

					} /* while */ 
					delete refinements;
					delete description;
				}while(!open_descriptions.EmptyP());
			}

		} /* while */ 
	} /* if */ 

	return true;
} /* rINDUCTIONHypothesis::learn_single_class */ 


